// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2015 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE file included with this file.
"use strict";

var EXPORTED_SYMBOLS = ["config"];

var NS = "theme-test://";

var { AddonManager } = module("resource://gre/modules/AddonManager.jsm");

var { Overlay, overlay } = require("overlay");
var { DOM, XHTML, XUL } = require("dom");
var { prefs } = require("prefs");
var { util } = require("util");
var { TESTS, media, image } = require("tests");

lazyRequire("config", ["config"]);
lazyRequire("io", ["File", "io"]);
lazyRequire("messages", ["_"]);

overlay.overlayWindow(["chrome://browser/content/browser.xul",
                       "chrome://navigator/content/navigator.xul"],
    Class("BrowserOverlay", Overlay, {
        after: [
            ["menu", { id: "webDeveloperMenu", xmlns: "xul", "xmlns:ns": NS },
                ["menuitem", { "ns:command": "test-theme", label: _("tools.test-theme.label"), accesskey: _("tools.test-theme.accesskey") }]],
            ["menu", { id: "appmenu_addons", xmlns: "xul", "xmlns:ns": NS },
                ["menuitem", { "ns:command": "test-theme", label: _("tools.test-theme.label"), accesskey: _("tools.test-theme.accesskey") }]],
        ],

        append: [
            ["popupset", { id: "mainPopupSet", xmlns: "xul", "xmlns:ns": NS },
                ["html:link", { rel: "stylesheet", type: "text/css", href: media("theme-test.css") }],

                ["panel", { id: "theme-test-panel-theme", key: "panel", noautohide: "true", onpopupshown: "this.overlay.positionPanel(true)" },
                    ["vbox", { collapsed: "true" },
                        ["hbox", {},
                            ["button", { type: "checkbox", "ns:command": "toggle-pinned", style: "min-width: 0; padding: 0;" }],
                            ["caption", { label: "Theme Test", flex: "1", class: "theme-test-title" }],
                            ["label", { key: "collapsedTitle", style: "padding-top: 2px" }],
                            ["separator", { style: "width: 1em" }],
                            ["hbox", {},
                                ["button", { label: "Prev", accesskey: "p", "ns:command": "prev-test", class: "plain theme-test-title-control" }],
                                ["label", { style: "min-width: 0; padding-top: 2px;", value: "/" }],
                                ["button", { label: "Next", accesskey: "n", "ns:command": "next-test", class: "plain theme-test-title-control" }]],
                            ["button", { label: "Show", accesskey: "h", "ns:command": "toggle", class: "plain theme-test-toggle" }]]],
                    ["vbox", {},
                        ["hbox", {},
                            ["button", { type: "checkbox", "ns:command": "toggle-pinned", style: "min-width: 0; padding: 0;" }],
                            ["caption", { label: "Theme Test", flex: "1", class: "theme-test-title" }],
                            ["button", { label: "Hide", accesskey: "h", "ns:command": "toggle", class: "plain theme-test-toggle" }]],
                        ["checkbox", { label: "Small toolbar buttons",
                                       accesskey: "S",
                                       key: "smallToolbarButtons",
                                       "ns:command": "small-toolbar-buttons" }],
                        ["checkbox", { label: "Menu bar",
                                       key: "menuBar",
                                       collapsed: "true",
                                       "ns:command": "menu-bar" }],

                        ["hbox", { flex: "1" },
                            ["vbox", {},
                                ["listbox", { class: "theme-test-tests", key: "tests", flex: "1" }],
                                ["hbox", {},
                                    ["button", { label: "Prev", accesskey: "p", "ns:command": "prev-test" }],
                                    ["button", { label: "Next", accesskey: "n", "ns:command": "next-test" }]]],
                            ["vbox", { key: "content", class: "theme-test-content" }]],

                        ["separator"],

                        ["hbox", { pack: "end" },
                            ["button", { "ns:command": "close", label: "Close", accesskey: "C" }]]]]],
        ],

        commands: {
            testTheme: function () { this.showPanel(); },

            close: function () {
                this.objects.panel.hidePopup();
                this.selectTest(null);
                this.objects.tests.selectedIndex = -1;
                if (this.tab && this.tab.parentNode)
                    this.window.gBrowser.removeTab(this.tab);
                this.tab = null;
            },

            menuBar: function (elem) {
                this.window.setToolbarVisibility(this.$("#toolbar-menubar")[0],
                                                 elem.checked);
            },

            smallToolbarButtons: function (elem) {
                let size = elem.checked ? "small" : "large";
                this.forEachToolbar(function (elem) {
                    elem.setAttribute("iconsize", size)
                });
                this.window.gNavToolbox.setAttribute("iconsize", size);
                this.window.gNavToolbox.customizeChange("iconsize");
                this.positionPanel();
            },

            toggle: function (elem) {
                let { panel } = this.objects;
                panel.children[0].collapsed ^= 1;
                panel.children[1].collapsed ^= 1;
                this.positionPanel();
            },

            togglePinned: function (elem) {
                this.pinned = !elem.checked;
            },

            nextTest: function (elem) {
                let { tests } = this.objects;
                tests.selectedIndex++;
            },
            prevTest: function (elem) {
                let { tests } = this.objects;
                tests.selectedIndex--;
            },
        },

        tests: TESTS,

        load: function load(window) {
        },

        _pinned: true,
        get pinned() this._pinned,
        set pinned(pinned) {
            let { panel } = this.objects;
            if (this._pinned != pinned) {
                DOM(panel).attr("titlebar", pinned ? null : "normal")
                          .before(panel);
                this.showPanel();
            }
            this._pinned = pinned;
        },

        ready: function ready(window) {
            let self = this;
            let { menuItem, tests } = this.objects;

            overlay.listen(this.window, "command", this.bound.onCommand);

            this.objects.panel.overlay = this;

            this.$(menuItem).command(function (event) {
                self.showPanel();
            });

            for (let [title, test] of iter(this.tests)) {
                test.title = title;
                util.trapErrors(function () {
                    if (!test.test || test.test.call(this))
                        DOM(tests).append(["listitem", { xmlns: XUL, label: title }]);
                }, this);
            }

            DOM(tests).listen("select", function () {
                self.selectTest(this.selectedItem && self.tests[this.selectedItem.label]);
            });
        },

        cleanup: function cleanup() {
            this.selectTest(null);
        },

        onCommand: function onCommand(event) {
            let command = this.commands[util.camelCase(DOM(event.originalTarget).attrNS(NS, "command") || "")];
            if (command)
                return util.trapErrors(command, this, event.originalTarget);
        },

        forEachToolbar: function forEachCustomizableToolbar(callback, addonBar) {
            let toolbox = this.window.gNavToolbox;

            function filter(elem) elem.localName == "toolbar" && elem.getAttribute("customizable") == "true";
            Array.filter(toolbox.childNodes, filter).forEach(callback, this);
            Array.filter(toolbox.externalToolbars, filter).forEach(callback, this);
            if (addonBar)
                callback.call(this, this.$("#addon-bar")[0]);
        },

        openSidebar: function openSidebar(id) {
            let { window } = this;
            let { document } = window;

            if (id)
                this.window.toggleSidebar(id, true);
            else if (!document.getElementById("sidebar-box").hidden)
                window.toggleSidebar();
        },

        selected: null,
        selectTest: function selectTest(test) {
            let { content } = this.objects;
            let self = this;

            if (this.undo) {
                this.undo.cleanup.forEach(function (c) { c.call(this, test); }, this);
                this.undo.windows.forEach(function (w) { try { w.close(); } catch (e) {} });
                this.undo.timers.forEach(function (t) { t.cancel(); });
                for (let [k, v] of iter(this.undo.prefs))
                    prefs.set(k, v);
                for (let [k, v] of iter(this.undo.toolbars))
                    this.window.setToolbarVisibility(this.$("#" + k)[0], !v);
            }

            let prev = this.selected;
            if (prev && prev.cleanup)
                util.trapErrors(prev.cleanup, this, prev, test);

            this.selected = test;
            this.undo = {
                cleanup: [],
                prefs: {},
                timers: [],
                toolbars: {},
                windows: []
            };
            this.undo.windows.pushMostRecent = function () {
                let win = services.windowMediator.getMostRecentWindow("");
                if (win && win != self.window)
                    this.push(win);
            };

            let title = "", label = "";
            if (test) {
                title = test.title;
                if (/^ /.test(title)) {
                    let tests = values(this.tests).toArray();
                    for (let i = tests.indexOf(test); i >= 0; i--)
                        if (/^\S/.test(tests[i].title)) {
                            title = tests[i].title + "/" + test.title.substr(2);
                            break;
                        }
                }
                label = "(" + title + ")";
            }
            this.objects.collapsedTitle.value = label;
            this.positionPanel();

            if (!test)
                test = {};

            this.openSidebar(test.sidebar);

            DOM(content).empty()
                        .append(["h3", { xmlns: XHTML }, title])
                        .append(test.content || [])
                        .find("a[href]")
                        .click(function (event) {
                            self.window.openUILink(this.href, event);
                            return false;
                        });

            if (test.action)
                test.action.call(this, test, prev);
            this.positionPanel();
        },

        setPref: function setPref(pref, value) {
            this.undo.prefs[pref] = prefs.get(pref, null);
            prefs.set(pref, value);
        },

        showPanel: function showPanel() {
            let anchor = this.window.gNavToolbox;
            let { panel } = this.objects;

            this.objects.menuBar.setAttribute("checked", this.$("#toolbar-menubar").attr("autohide") == "true");
            this.objects.smallToolbarButtons.setAttribute("checked", this.window.gNavToolbox.getAttribute("iconsize") == "small");

            panel.openPopup(anchor, "after_start", 0, 0);
            this.positionPanel(true);
        },

        positionPanel: function positionPanel(force) {
            if (!force && !this.pinned)
                return;

            let anchor = this.window.gNavToolbox;
            let { panel } = this.objects;

            panel.moveTo(anchor.boxObject.screenX + (anchor.boxObject.width - panel.boxObject.width) / 2,
                         anchor.boxObject.screenY + anchor.boxObject.height);
        },

        openIdentityBox: function openIdentityBox() {
            this.$("#identity-box").click();
        },

        openToolbox: function openToolbox(panel, callback) {
            let { gBrowser, gDevTools } = this.window;

            try {
                var devtools = Cu.import("resource:///modules/devtools/Target.jsm", {});
            }
            catch (e) {
                var { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
            }

            let { TargetFactory } = devtools;

            let target = TargetFactory.forTab(gBrowser.mCurrentTab);
            return gDevTools.showToolbox(target, panel).then(toolbox => {
                toolbox.fireCustomKey(panel);

                this.undo.cleanup.push(function (nextTest) {
                    if (!nextTest.devToolsPane)
                        gDevTools.closeToolbox(target);
                });
                if (callback)
                    callback.call(this, toolbox.getCurrentPanel(), toolbox, target);
            });
        },

        inspectNode: function inspectNode(node, callback) {
            let { InspectorUI } = this.window;
            if (InspectorUI) {
                InspectorUI.openInspectorUI(logo[0]);
                if (callback)
                    callback.call(this);
                return;
            }

            this.openToolbox("inspector", (inspector, toolbox) => {
                inspector.selection.setNode(node, "browser-context-menu");
                if (callback)
                    callback.call(this, inspector, toolbox);
            });
        },

        loadPage: function loadPage(url, callback) {
            let { gBrowser } = this.window;

            if (!this.tab || !this.tab.parentNode)
                this.tab = gBrowser.addTab();
            gBrowser.selectedTab = this.tab;

            let self = this;
            let browser = this.tab.linkedBrowser;

            if (callback)
                DOM(browser).once("DOMContentLoaded", function onload(event) {
                    callback.call(self, browser);
                });
            browser.loadURI(url);
        }
    }));

// vim: set sw=4 sts=4 et ft=javascript:
